﻿using System;
using CacheNaga.HashAlgorithms;

namespace CacheNaga
{
	internal static class Helper
	{
		/// <summary>
		/// 安全的将UInt64转换为Int32?类型
		/// </summary>
		/// <param name="value"></param>
		/// <returns></returns>
		public static Int32? SafeConvertToNullableInt32(UInt64? value)
		{
			if (!value.HasValue)
				return null;

			//不能大于Int32的最大值(与该值用Int64表示的方式比较)
			if (value > 0x7fffffffL)
			{
				//throw new InvalidCastException("无法将System.UInt64结果转换为System.Int32类型");
				return null;
			}

			return Convert.ToInt32(value.Value);
		}

		/// <summary>
		/// 安全的将Int32转换为UInt64类型
		/// </summary>
		/// <param name="value"></param>
		/// <returns></returns>
		public static UInt64 ConvertInt32ToUInt64(Int32 value)
		{
			//UInt64的最小值是0
			if (value < 0)
			{
				throw new InvalidCastException("无法将System.Int32参数转换为System.UInt64类型");
			}
			return Convert.ToUInt64(value);
		}

		/// <summary>
		/// 检查key是否合法
		/// </summary>
		/// <param name="key">要检查的key</param>
		public static void ValidateKey(string key)
		{
			if (key == null)
			{
				throw new ArgumentNullException("Key不能为null.");
			}
			if (key.Length == 0)
			{
				throw new ArgumentException("Key不能是empty.");
			}
			if (key.Length > 250)
			{
				throw new ArgumentException("Key的长度不能超过250个字符");
			}
			foreach (char c in key)
			{
				if (c <= 32)
				{
					throw new ArgumentException("key不能包含空格和控制性字符");
				}
			}
		}

		//Unix使用的是GMT时间,将.net的时间转换为GMT方式计算
		private static DateTime epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);

		/// <summary>
		/// 获取GMT时间
		/// </summary>
		/// <param name="datetime"></param>
		/// <returns></returns>
		public static int GetUnixTime(DateTime datetime)
		{
			return (int)(datetime.ToUniversalTime() - epoch).TotalSeconds;
		}

		#region Hash相关

		/// <summary>
		/// 使用改进的MD5算法哈希key
		/// </summary>
		/// <param name="key">要哈希的key</param>
		/// <returns>该key的哈希值</returns>
		public static uint Hash(string key)
		{
			//ValidateKey(key);
			//return BitConverter.ToUInt32(new ModifiedFNV1_32().ComputeHash(Encoding.UTF8.GetBytes(key)), 0);
			return EnhancedMD5HashAlgorithm.Md5(key);
		}

		/// <summary>
		/// 重hash用户指定的hash值
		/// </summary>
		/// <param name="hashvalue">用户提供的hash值</param>
		/// <returns>重hash的值</returns>
		public static uint Hash(uint hashvalue)
		{
			//return BitConverter.ToUInt32(new ModifiedFNV1_32().ComputeHash(BitConverter.GetBytes(hashvalue)), 0);
			return EnhancedMD5HashAlgorithm.Md5(System.Text.Encoding.UTF8.GetString(BitConverter.GetBytes(hashvalue)));
		}

		/// <summary>
		/// 哈希string数组为uint数组
		/// </summary>
		public static uint[] Hash(string[] keys)
		{
			uint[] result = new uint[keys.Length];
			for (int i = 0; i < keys.Length; i++)
			{
				result[i] = Hash(keys[i]);
			}
			return result;
		}

		/// <summary>
		/// 重hash用户指定的hash数组
		/// </summary>
		public static uint[] Hash(uint[] hashvalues)
		{
			uint[] result = new uint[hashvalues.Length];
			for (int i = 0; i < hashvalues.Length; i++)
			{
				result[i] = Hash(hashvalues[i]);
			}
			return result;
		}

		#endregion
	}
}
